/**
 *Copyright (c) 2024 watereyes
 * workflow is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.koron.workflow.api.controller;

import com.koron.workflow.common.bean.MessageEntity;
import com.koron.workflow.common.exception.WorkflowException;

import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.ADOConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.swan.bean.MessageBean;

import com.google.gson.Gson;
import com.koron.workflow.api.bean.query.ProcessCommitQueryBean;
import com.koron.workflow.api.bean.query.ProcessListQueryBean;
import com.koron.workflow.api.bean.query.ProcessQueryBean;
import com.koron.workflow.api.bean.query.ProcessStartQueryBean;
import com.koron.workflow.api.service.WorkflowService;
import com.koron.workflow.api.util.ApiUtils;
import com.koron.workflow.api.util.ExceptionUtils;
import com.koron.workflow.common.util.BusinessCode;
import com.koron.workflow.workflowDesign.bean.ProcessBean;

/**
 * 流程平台对外接口访问
 * @author 周利斌
 * @date 2020-04-13
 * 
 */
@Controller
@RequestMapping("/process")
public class WorkflowController {
	
	private static Logger log = LoggerFactory.getLogger(WorkflowController.class);
	
	@Autowired
	private WorkflowService workflowService;
 
    @ResponseBody
	@RequestMapping(value = "/start.htm", method = RequestMethod.POST)
	public MessageBean<?> start(@RequestBody ProcessStartQueryBean param){
		try {
			if(StringUtils.isEmpty(param.getSecret())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "secret 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getSetCode())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "setCode 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getProcessCode())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "processCode 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getBillId())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "billId 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getOperator())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "operator 参数不能为空", Void.class);
			}
			if(param.getFormVariables() == null) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "formVariables 参数不能为空", Void.class);
			}
			//秘钥验证 已包含时间戳校验
			MessageBean<?> message = ApiUtils.secretVerify(param.getSecret());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			String appCode = (String) message.getData();
			//判断当前应用是否有操作该流程模板的权限
			message = ApiUtils.processPermission(appCode, param.getProcessCode(), param.getSetCode());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			ProcessBean process = (ProcessBean) message.getData();
			param.setAppCode(appCode);
			param.setProcessId(process.getId());
			message = ADOConnection.runTask(workflowService, "start", MessageBean.class, param);
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("流程启动成功, 单据：{} 流程模板：{} 操作人：{}", param.getBillId(), param.getProcessCode(), param.getOperator());
			}else {
				log.info("流程启动失败：{} 参数：{}", message.getDescription(), new Gson().toJson(param));
			}
			return message;
		}catch(Exception ex) {
			log.error("流程启动失败：", ex);
			String message = "流程启动失败";
			WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
			return MessageBean.create(BusinessCode.FAILURE.getCode(), message, Void.class);
		}
	}
	
	/**
	 * 流程提交
	 * @param param
	 * @return
	 */
    @ResponseBody
	@RequestMapping(value = "/submit.htm", method = RequestMethod.POST)
	public MessageBean<?> submit(@RequestBody ProcessCommitQueryBean param){
		try {
			if(StringUtils.isEmpty(param.getSecret())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "secret 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getSetCode())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "setCode 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getProcessCode())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "processCode 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getBillId())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "billId 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getOperator())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "operator 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(param.getTaskId())) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "taskId 参数不能为空", Void.class);
			}
			if(param.getOperation() == null) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "operation 参数不能为空", Void.class);
			}
			//秘钥验证 已包含时间戳校验
			MessageBean<?> message = ApiUtils.secretVerify(param.getSecret());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			String appId = (String) message.getData();
			//判断当前应用是否有操作改流程模板的权限
			message = ApiUtils.processPermission(appId, param.getProcessCode(), param.getSetCode());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			message = ADOConnection.runTask(workflowService, "submit", MessageBean.class, param);
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("流程提交成功, 单据：{} 流程模板：{} 表单参数：{}, 操作人：{}", param.getBillId(), param.getProcessCode(), param.getFormVariables(), param.getOperator());
			}else {
				log.info("流程提交失败：{} 参数：{}", message.getDescription(), new Gson().toJson(param));
			}
			return message;
		}catch(Exception ex) {
			String message = "流程提交失败";
			WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
			log.error("流程提交失败：", ex);
			return MessageBean.create(BusinessCode.FAILURE.getCode(), message, Void.class);
		}
	}
	
	@RequestMapping(value = "/view.htm", method = RequestMethod.GET)
	public ModelAndView view(@RequestParam(required = true) String secret, String taskId, String processInstanceId, String billId, @RequestParam(required = true) String operator, @RequestParam(required = true) String setCode, @RequestParam(required = true) String processCode){
		try {
			//秘钥验证 已包含时间戳校验
			secret = secret.trim().replace(" ", "+");
			MessageBean<?> message = ApiUtils.secretVerify(secret);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return new ModelAndView();
			}
			String appId = (String) message.getData();
			//判断当前应用是否有操作改流程模板的权限
			message = ApiUtils.processPermission(appId, processCode, setCode);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return new ModelAndView();
			}
			message = ADOConnection.runTask(workflowService, "view", MessageBean.class, taskId, processInstanceId, billId, operator, setCode, processCode);
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("获取流程表单页面成功, taskId：{} processInstanceId：{} billId：{} operator：{}", taskId, processInstanceId, billId, operator);
			}else {
				log.info("流程提交失败：{}", message.getDescription());
			}
			return (ModelAndView) message.getData();
		}catch(Exception ex) {
			ex.printStackTrace();
			log.error("获取流程表单页面失败：", ex);
			return new ModelAndView();
		}
	}
	
	@ResponseBody
	@RequestMapping(value = "/history.htm", method = RequestMethod.GET)
	public MessageBean<?> history(@RequestParam(required = true) String secret, @RequestParam(required = true) String setCode, @RequestParam(required = true) String processCode, @RequestParam(required = true) String billId){
		try {
			if(StringUtils.isEmpty(secret)) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "secret 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(setCode)) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "setCode 参数不能为空", Void.class);
			}
			if(StringUtils.isEmpty(processCode)) {
				return MessageBean.create(BusinessCode.FAILURE.getCode(), "processCode 参数不能为空", Void.class);
			}
			secret = secret.trim().replace(" ", "+");
			//秘钥验证 已包含时间戳校验
			MessageBean<?> message = ApiUtils.secretVerify(secret);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			String appId = (String) message.getData();
			//判断当前应用是否有操作改流程模板的权限
			message = ApiUtils.processPermission(appId, processCode, setCode);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			message = ADOConnection.runTask(workflowService, "history", MessageBean.class, setCode, processCode, billId);
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("获取流程历史轨迹成功, setCode：{} processCode：{} ", setCode, processCode);
			}else {
				log.info("获取流程历史轨迹失败：{}", message.getDescription());
			}
			return message;
		}catch(Exception ex) {
			String message = "获取流程历史轨迹失败";
			WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
			log.error("获取流程历史轨迹失败：", ex);
			return MessageBean.create(BusinessCode.FAILURE.getCode(), message, Void.class);
		}
	}
   
    @ResponseBody
    @RequestMapping(value = "/list.htm", method = RequestMethod.GET)
    public MessageEntity<?> list(ProcessListQueryBean bean) {
    	try {
    		if(StringUtils.isEmpty(bean.getSecret())) {
    			return MessageEntity.fail("secret 参数不能为空", BusinessCode.FAILURE.getCode());
    		}
    		if(bean.getType() == null) {
    			return MessageEntity.fail("type 参数不能为空", BusinessCode.FAILURE.getCode());
    		}
    		if(bean.getType() != 6 && StringUtils.isEmpty(bean.getOperator())) {
    			return MessageEntity.fail("operator 参数不能为空", BusinessCode.FAILURE.getCode());
    		}
    		//秘钥验证 已包含时间戳校验
    		bean.setSecret(bean.getSecret().trim().replace(" ", "+"));
			MessageBean<?> message = ApiUtils.secretVerify(bean.getSecret());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return MessageEntity.fail(message.getDescription(), BusinessCode.FAILURE.getCode());
			}
			String appCode = (String) message.getData();
			bean.setAppCode(appCode);
			MessageEntity<?> result = ADOConnection.runTask(workflowService, "list", MessageEntity.class, bean);
			if(result.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("获取流程任务列表成功 ");
			}else {
				log.info("获取流程任务列表失败：{} 参数：{}", result.getDescription(), new Gson().toJson(bean));
			}
            return result;
    	}catch(Exception ex) {
    		String message = "获取流程任务列表失败";
    		WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
    		log.error("获取流程任务列表失败：", ex);
    		return MessageEntity.fail(message, BusinessCode.FAILURE.getCode());
    	}
    }

    @ResponseBody
    @RequestMapping(value = "/define.htm", method = RequestMethod.GET)
    public MessageBean<?> define(@RequestParam(required = true) String secret, @RequestParam(required = true) String setCode, @RequestParam(required = true) String processCode) {
    	try {
    		if(StringUtils.isEmpty(secret)) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "secret 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(setCode)) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "setCode 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(processCode)) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "processCode 参数不能为空", Void.class);
    		}
    		//秘钥验证 已包含时间戳校验
    		secret = secret.trim().replace(" ", "+");
			MessageBean<?> message = ApiUtils.secretVerify(secret);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			String appCode = (String) message.getData();
			//判断当前应用是否有操作改流程模板的权限
			message = ApiUtils.processPermission(appCode, processCode, setCode);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			message = ADOConnection.runTask(workflowService, "define", MessageBean.class, setCode, processCode);
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("获取流程节点信息成功 ");
			}else {
				log.info("获取流程节点信息失败：{} 参数：{}", message.getDescription(), setCode + "_" + processCode);
			}
            return message;
    	}catch(Exception ex) {
    		String message = "获取流程节点信息失败";
    		WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
    		log.error("获取流程节点信息失败：", ex);
			return MessageBean.create(BusinessCode.FAILURE.getCode(), message, Void.class);
    	}
    }

	/**
	 *
	 * @param query
	 * @return
	 */
	@ResponseBody
    @RequestMapping(value = "/suspend.htm", method = RequestMethod.POST)
    public MessageBean<?> suspend(@RequestBody ProcessQueryBean query) {
    	try {
    		if(StringUtils.isEmpty(query.getSecret())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "secret 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getSetCode())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "setCode 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getProcessCode())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "processCode 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getProcessInstanceId())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "processInstanceId 参数不能为空", Void.class);
    		}
    		String secret = query.getSecret();
    		//秘钥验证 已包含时间戳校验
    		secret = secret.trim().replace(" ", "+");
			MessageBean<?> message = ApiUtils.secretVerify(secret);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			String appCode = (String) message.getData();
			//判断当前应用是否有操作改流程模板的权限
			message = ApiUtils.processPermission(appCode, query.getProcessCode(), query.getSetCode());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			message = workflowService.suspend(query.getProcessInstanceId());
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("流程挂起操作成功 {}", query.getProcessInstanceId());
			}else {
				log.info("流程挂起操作失败：{} 参数：{} 单据：{}", message.getDescription(), query.getSetCode() + "_" + query.getProcessCode(), query.getProcessInstanceId());
			}
            return message;
    	}catch(Exception ex) {
    		String message = "流程挂起操作失败";
    		WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
    		log.error("流程挂起操作失败：", ex);
			return MessageBean.create(BusinessCode.FAILURE.getCode(), message, Void.class);
    	}
    }

	/**
	 *
	 * @param query
	 * @return
	 */
	@ResponseBody
    @RequestMapping(value = "/recovery.htm", method = RequestMethod.POST)
    public MessageBean<?> recovery(@RequestBody ProcessQueryBean query) {
    	try {
    		if(StringUtils.isEmpty(query.getSecret())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "secret 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getSetCode())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "setCode 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getProcessCode())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "processCode 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getProcessInstanceId())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "processInstanceId 参数不能为空", Void.class);
    		}
    		String secret = query.getSecret();
    		//秘钥验证 已包含时间戳校验
    		secret = secret.trim().replace(" ", "+");
			MessageBean<?> message = ApiUtils.secretVerify(secret);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			String appCode = (String) message.getData();
			//判断当前应用是否有操作改流程模板的权限
			message = ApiUtils.processPermission(appCode, query.getProcessCode(), query.getSetCode());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			message = workflowService.recovery(query.getProcessInstanceId());
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("流程恢复操作成功 {}", query.getProcessInstanceId());
			}else {
				log.info("流程恢复操作失败：{} 参数：{} 单据：{}", message.getDescription(), query.getSetCode() + "_" + query.getProcessCode(), query.getProcessInstanceId());
			}
            return message;
    	}catch(Exception ex) {
    		String message = "流程恢复操作失败";
    		WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
    		log.error("流程恢复操作失败：", ex);
			return MessageBean.create(BusinessCode.FAILURE.getCode(), message, Void.class);
    	}
    }
    
    @ResponseBody
    @RequestMapping(value = "/deleteProcess.htm", method = RequestMethod.POST)
    public MessageBean<?> initProcess(@RequestBody ProcessQueryBean query) {
    	try {
    		if(StringUtils.isEmpty(query.getSecret())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "secret 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getSetCode())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "setCode 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getProcessCode())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "processCode 参数不能为空", Void.class);
    		}
    		if(StringUtils.isEmpty(query.getProcessInstanceId())) {
    			return MessageBean.create(BusinessCode.FAILURE.getCode(), "processInstanceId 参数不能为空", Void.class);
    		}
    		String secret = query.getSecret();
    		//秘钥验证 已包含时间戳校验
    		secret = secret.trim().replace(" ", "+");
			MessageBean<?> message = ApiUtils.secretVerify(secret);
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			String appCode = (String) message.getData();
			//判断当前应用是否有操作改流程模板的权限
			message = ApiUtils.processPermission(appCode, query.getProcessCode(), query.getSetCode());
			if(message.getCode() != BusinessCode.SUCCESS.getCode()) {
				return message;
			}
			message = ADOConnection.runTask(workflowService, "deleteProcess", MessageBean.class, query.getProcessInstanceId());
			if(message.getCode() == BusinessCode.SUCCESS.getCode()) {
				log.info("初始化流程成功 单据：{}", query.getProcessInstanceId());
			}else {
				log.info("初始化流程失败：{} 参数：{} 单据：{}", message.getDescription(), query.getSetCode() + "_" + query.getProcessCode(), query.getProcessInstanceId());
			}
            return message;
    	}catch(Exception ex) {
    		String message = "初始化流程失败";
    		WorkflowException workflowException = ExceptionUtils.getWorkflowException(ex);
			if(workflowException != null) {
				message = workflowException.getMessage();
			}
    		log.error("初始化流程失败：", ex);
			return MessageBean.create(BusinessCode.FAILURE.getCode(), message, Void.class);
    	}
    }
}
